#include 	"ServerUnix.h"
#include	"StockMessage.hpp"
#include	<fstream>
#include	<utility>
// Constructor / Destructor

using namespace std;

extern StockMessage<std::pair<std::string, int> >		inputList;
extern StockMessage<std::pair<std::string, int> >		outputList;

// Constructor / Destructor

ServerUnix::ServerUnix()
{
}

ServerUnix::~ServerUnix()
{

}




// Public Methods

void		ServerUnix::LaunchServer()
{
  if (HandleListen() >= 0)
    HandleSelect();
}

// Private Methods

int	ServerUnix::HandleListen()
{
	struct sockaddr_in	addr;
	int len;
	
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = INADDR_ANY;
	_servSock = socket(AF_INET, SOCK_STREAM, 0);
	if (_servSock < 0)
	    return (-1);
	len = sizeof(addr);
	if (bind(_servSock, (struct sockaddr *)&addr, sizeof(addr)) == -1)
	  {
	    std::cout << "Bind Failed\n" << std::endl;
	    return (-2);
	  }
	listen(_servSock, SOMAXCONN);
	return (0);
}

int	ServerUnix::HandleSelect()
{
  fd_set				StaticRFdSet;
  fd_set				RFdSet;
  int					max = _servSock;
  int					checkSock;
  const pair<string, int>		*response = NULL;
  
  FD_ZERO(&StaticRFdSet);
  FD_SET(_servSock, &StaticRFdSet);
  for (;;)
    {
      RFdSet = StaticRFdSet;
      if (select(max + 1, &RFdSet, NULL, NULL, NULL) < 1)
	std::cout << "Select Error" << std::endl;
      for(checkSock = 0; checkSock < max + 1; checkSock++)
	{
	  if (FD_ISSET(checkSock, &RFdSet)) 
	    {
	      if (checkSock == _servSock)
		{
		  std::cout << "New Client" << std::endl;
		  max = NewClient(&StaticRFdSet, max);
		}
	      else
		{
		  std::cout << "New Message Received:\n";
		  HandleMsg(checkSock, &StaticRFdSet, &max);
		}
	    }
	}
      response = outputList.getWithoutPop();
      if (response != NULL && FD_ISSET(response->second, &StaticRFdSet))
	{
	  response = outputList.getMessage();
	  send(response->second, (response->first).c_str(), (response->first).size(), 0);
	  //cout << (response->first).c_str() << endl;
	  response = NULL;
	}
    }
  return (0);
}

int			ServerUnix::NewClient(fd_set *StaticRFdSet, int max)
{
	socklen_t					lenCliAddr = sizeof(struct sockaddr_in);
	struct sockaddr_in	cliAddr;
	int					cliSock;

	cliSock = accept(_servSock, (struct sockaddr *)&cliAddr, &lenCliAddr);
	FD_SET(cliSock, StaticRFdSet);
	if (max < cliSock)
		max = cliSock;
	return (max);
}

std::string	ServerUnix::HandleMsg(int checkSock, fd_set *StaticRFdSet, int *max)
{
	std::string			msg = "";
	int					it = 0;
	int					reading;
	char				buf[BUFLEN + 1];
	int					max_old;
	std::pair<std::string, int>	*myRequest;
	bool flag = false;
	unsigned int		pos;

	msg.clear();
	reading = BUFLEN;
	while ((reading = recv(checkSock, buf, BUFLEN, MSG_DONTWAIT)) > 0)
	{
	  buf[reading] = '\0';
	  myBuffer.insert(it, buf, reading);
	  it += reading;
	  flag = true;
	}
	if (flag == false)
 	  FD_CLR(checkSock, StaticRFdSet);
	else
	  {
	    pos = myBuffer.find("\r\n");
	    if (pos != std::string::npos)
	      {
		msg = myBuffer.substr(0, pos);
		myBuffer.erase(0, pos + 2);
		myRequest = new std::pair<std::string, int>;
		myRequest->first = msg;
		myRequest->second = checkSock;
		inputList.addMessage(myRequest);
	      }
	  }
	if (checkSock == *max)
	  {
	    max_old = *max;
	    *max = 0;
	    for (checkSock = 0; checkSock <= max_old ; checkSock++)
	      {
		if ((checkSock >= *max) && (FD_ISSET(checkSock, StaticRFdSet)))
		  *max = checkSock;
	      }
	  }
	return (msg);
}
void		ServerUnix::closeConnection()
{
  if (_servSock)
    close(_servSock);
}
